home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Tools / Win95 Secrets / SETUP.Z / APISPYLD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-19  |  14.1 KB  |  461 lines

  1. //==================================
  2. // APISPYLD - Matt Pietrek 1995
  3. // FILE: APISPYLD.C
  4. //==================================
  5. #include <windows.h>
  6. #include <stddef.h>
  7. #pragma hdrstop
  8. #include "apispyld.h"
  9.  
  10. //======================== Global Variables =================================
  11. char SzINISection[] = "Options";
  12. char SzINICmdLineKey[] = "CommandLine";
  13. char SzINIFile[] = "APISPY32.INI";
  14. char SzCmdLine[MAX_PATH];
  15.  
  16. BOOL FFirstBreakpointHit = FALSE, FSecondBreakpointHit = FALSE;
  17.  
  18. PROCESS_INFORMATION ProcessInformation;
  19. CREATE_PROCESS_DEBUG_INFO ProcessDebugInfo;
  20.  
  21. CONTEXT OriginalThreadContext, FakeLoadLibraryContext;
  22. PVOID PInjectionPage;
  23.  
  24. #define PAGE_SIZE 4096
  25. BYTE OriginalCodePage[PAGE_SIZE];
  26. BYTE NewCodePage[PAGE_SIZE];
  27.  
  28. //======================== Code =============================================
  29.  
  30. //
  31. // Function prototypes
  32. //
  33. BOOL  CALLBACK APISPY32DlgProc(HWND, UINT, WPARAM, LPARAM);
  34. void  Handle_WM_COMMAND(HWND hWndDlg, WPARAM wParam, LPARAM lParam);
  35. void  Handle_WM_INITDIALOG(HWND hWndDlg, WPARAM wParam, LPARAM lParam);
  36. BOOL  GetProgramName(HWND hWndOwner, PSTR szFile, unsigned nFileBuffSize);
  37. BOOL  LoadProcessForSpying(PSTR SzCmdLine);
  38. void  DebugLoop(void);
  39. DWORD HandleDebugEvent( DEBUG_EVENT * event );
  40. void  HandleException(LPDEBUG_EVENT lpEvent, PDWORD continueStatus);
  41. void  EmptyMsgQueueOfUselessMessages(void);
  42. BOOL  InjectSpyDll(void);
  43. BOOL  ReplaceOriginalPagesAndContext(void);
  44. PVOID FindUsablePage(HANDLE hProcess, PVOID PProcessBase);
  45. BOOL  GetSpyDllName(PSTR buffer, UINT cBytes);
  46.  
  47.  
  48. int APIENTRY WinMain( HANDLE hInstance, HANDLE hPrevInstance,
  49.                         LPSTR lpszCmdLine, int nCmdShow )
  50. {
  51.     // This dialog returns 0 if the user pressed cancel
  52.     while ( 0 != DialogBox(hInstance, "APISPY32_LOAD_DLG", 0,
  53.                             (DLGPROC)APISPY32DlgProc) )
  54.     {
  55.         if ( LoadProcessForSpying(SzCmdLine) )
  56.         {
  57.             DebugLoop();
  58.             break;
  59.         }
  60.  
  61.         MessageBox(0, "Unable to start program", 0, MB_OK);
  62.     }
  63.     
  64.     return 0;
  65. }
  66.  
  67. BOOL CALLBACK APISPY32DlgProc(HWND hWndDlg, UINT msg,
  68.                               WPARAM wParam, LPARAM lParam)
  69. {
  70.     switch ( msg )
  71.     {
  72.         case WM_COMMAND:
  73.             Handle_WM_COMMAND(hWndDlg, wParam, lParam);
  74.             return TRUE;
  75.         case WM_INITDIALOG:
  76.             Handle_WM_INITDIALOG(hWndDlg, wParam, lParam);
  77.             return TRUE;
  78.         case WM_CLOSE:
  79.             EndDialog(hWndDlg, 0);
  80.             return FALSE;
  81.     }
  82.     
  83.     return FALSE;
  84. }
  85.  
  86. void Handle_WM_COMMAND(HWND hWndDlg, WPARAM wParam, LPARAM lParam)
  87. {
  88.     if ( wParam == IDC_RUN )
  89.     {
  90.         if ( GetWindowText( GetDlgItem(hWndDlg, IDC_CMDLINE),
  91.                             SzCmdLine, sizeof(SzCmdLine)) )
  92.         {
  93.             WritePrivateProfileString(SzINISection, SzINICmdLineKey,
  94.                                         SzCmdLine, SzINIFile);
  95.             EndDialog(hWndDlg, 1);  // Return TRUE
  96.         }
  97.         else
  98.         {
  99.             MessageBox( hWndDlg, "No program selected", 0, MB_OK);
  100.         }
  101.     }
  102.     else if ( wParam == IDC_FILE )
  103.     {
  104.         if ( GetProgramName(hWndDlg, SzCmdLine, sizeof(SzCmdLine)) )
  105.             SetWindowText( GetDlgItem(hWndDlg, IDC_CMDLINE), SzCmdLine );
  106.     }
  107.     else if ( wParam == IDCANCEL )
  108.     {
  109.         EndDialog(hWndDlg, 0);
  110.     }
  111. }
  112.  
  113. void Handle_WM_INITDIALOG(HWND hWndDlg, WPARAM wParam, LPARAM lParam)
  114. {
  115.     GetPrivateProfileString(SzINISection, SzINICmdLineKey, "", SzCmdLine,
  116.                             sizeof(SzCmdLine), SzINIFile);
  117.     SetWindowText( GetDlgItem(hWndDlg, IDC_CMDLINE), SzCmdLine );
  118. }
  119.  
  120. static char szFilter1[] = "Programs (*.EXE)\0*.EXE\0";
  121.  
  122. BOOL GetProgramName(HWND hWndOwner, PSTR szFile, unsigned nFileBuffSize)
  123. {
  124.     OPENFILENAME ofn;
  125.  
  126.     szFile[0] = 0;
  127.  
  128.     memset(&ofn, 0, sizeof(OPENFILENAME));
  129.     
  130.     ofn.lStructSize = sizeof(OPENFILENAME);
  131.     ofn.hwndOwner = hWndOwner;
  132.     ofn.lpstrFilter = szFilter1;
  133.     ofn.nFilterIndex = 1;
  134.     ofn.lpstrFile= szFile;
  135.     ofn.nMaxFile = nFileBuffSize;
  136.     ofn.lpstrFileTitle = 0;
  137.     ofn.nMaxFileTitle = 0;
  138.     ofn.lpstrInitialDir = 0;
  139.     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
  140.     
  141.     return GetOpenFileName(&ofn);
  142. }
  143.  
  144. BOOL LoadProcessForSpying(PSTR SzCmdLine)
  145. {
  146.     STARTUPINFO startupInfo;
  147.     
  148.     memset(&startupInfo, 0, sizeof(startupInfo));
  149.     startupInfo.cb = sizeof(startupInfo);
  150.         
  151.     return CreateProcess(
  152.                 0,                          // lpszImageName
  153.                 SzCmdLine,                  // lpszCommandLine
  154.                 0,                          // lpsaProcess
  155.                 0,                          // lpsaThread
  156.                 FALSE,                      // fInheritHandles
  157.                 DEBUG_ONLY_THIS_PROCESS,    // fdwCreate
  158.                 0,                          // lpvEnvironment
  159.                 0,                          // lpszCurDir
  160.                 &startupInfo,               // lpsiStartupInfo
  161.                 &ProcessInformation         // lppiProcInfo
  162.                 );
  163. }
  164.  
  165. void DebugLoop(void)
  166. {
  167.     DEBUG_EVENT event;
  168.     DWORD continueStatus;
  169.     BOOL fWin32s;
  170.     BOOL fWaitResult;
  171.     
  172.     fWin32s = (GetVersion() & 0xC0000000) == 0x80000000;
  173.     
  174.     while ( 1 )
  175.     {
  176.         fWaitResult = WaitForDebugEvent(&event, INFINITE);
  177.             
  178.         if ( (fWaitResult == FALSE) && fWin32s )
  179.         {
  180.             EmptyMsgQueueOfUselessMessages();
  181.             continue;
  182.         }
  183.         
  184.         continueStatus = HandleDebugEvent( &event );
  185.         
  186.         if ( event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT )
  187.             return;
  188.         
  189.         ContinueDebugEvent( event.dwProcessId,
  190.                             event.dwThreadId,
  191.                             continueStatus );
  192.     }
  193. }
  194.  
  195. PSTR SzDebugEventTypes[] = 
  196. {
  197. "",
  198. "EXCEPTION",
  199. "CREATE_THREAD",
  200. "CREATE_PROCESS",
  201. "EXIT_THREAD",
  202. "EXIT_PROCESS",
  203. "LOAD_DLL",
  204. "UNLOAD_DLL",
  205. "OUTPUT_DEBUG_STRING",
  206. "RIP",
  207. };
  208.  
  209. DWORD HandleDebugEvent( DEBUG_EVENT * event )
  210. {
  211.     DWORD continueStatus = DBG_CONTINUE;
  212.     // char buffer[1024];
  213.  
  214.     // wsprintf(buffer, "Event: %s\r\n",
  215.     //          SzDebugEventTypes[event->dwDebugEventCode]);
  216.     // OutputDebugString(buffer);
  217.  
  218.  
  219.     if ( event->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT )
  220.     {
  221.         ProcessDebugInfo = event->u.CreateProcessInfo;
  222.     }
  223.     else if ( event->dwDebugEventCode == EXCEPTION_DEBUG_EVENT )
  224.     {
  225.         HandleException(event, &continueStatus);
  226.     }
  227.         
  228.     return continueStatus;
  229. }
  230.  
  231. void HandleException(LPDEBUG_EVENT lpEvent, PDWORD continueStatus)
  232. {
  233.     // char buffer[128];
  234.     // wsprintf(buffer, "Exception code: %X  Addr: %08X\r\n",
  235.     //          lpEvent->u.Exception.ExceptionRecord.ExceptionCode,
  236.     //          lpEvent->u.Exception.ExceptionRecord.ExceptionAddress);
  237.     // OutputDebugString(buffer);
  238.             
  239.                 
  240.     if ( lpEvent->u.Exception.ExceptionRecord.ExceptionCode
  241.             == EXCEPTION_BREAKPOINT )
  242.     {
  243.         if ( FFirstBreakpointHit == FALSE )
  244.         {
  245.             InjectSpyDll();
  246.             FFirstBreakpointHit = TRUE;
  247.         }
  248.         else if ( FSecondBreakpointHit == FALSE )
  249.         {
  250.             ReplaceOriginalPagesAndContext();
  251.             FSecondBreakpointHit = TRUE;
  252.         }
  253.         
  254.         *continueStatus = DBG_CONTINUE;
  255.     }
  256.     else
  257.     {
  258.         *continueStatus = DBG_EXCEPTION_NOT_HANDLED;
  259.     }
  260. }
  261.  
  262. void EmptyMsgQueueOfUselessMessages(void)
  263. {
  264.     MSG msg;        // See PeekMessage loop for explanation of idiocy
  265.  
  266.     // Win32s idiocy puts W32s_Debug_Msg message in our message queue
  267.     // Dispose of them!  They're useless!
  268.     while ( PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
  269.     {
  270.         if ( msg.hwnd )
  271.             DispatchMessage(&msg);
  272.     }
  273. }
  274.  
  275. #pragma pack ( 1 )
  276. typedef struct
  277. {
  278.     WORD    instr_SUB;
  279.     DWORD   operand_SUB_value;
  280.     BYTE    instr_PUSH;
  281.     DWORD   operand_PUSH_value;
  282.     BYTE    instr_CALL;
  283.     DWORD   operand_CALL_offset;
  284.     BYTE    instr_INT_3;
  285.     char    data_DllName[1];
  286. } FAKE_LOADLIBRARY_CODE, * PFAKE_LOADLIBRARY_CODE;
  287.  
  288. BOOL InjectSpyDll(void)
  289. {
  290.     BOOL retCode;
  291.     DWORD cBytesMoved;
  292.     char szSpyDllName[MAX_PATH];
  293.     FARPROC pfnLoadLibrary;
  294.     PFAKE_LOADLIBRARY_CODE pNewCode;
  295.     
  296.     // =====================================================================
  297.     // Phase 1 - Locating addresses of important things
  298.     // =====================================================================
  299.         
  300.     pfnLoadLibrary = GetProcAddress( GetModuleHandle("KERNEL32.DLL"),
  301.                                      "LoadLibraryA" );
  302.     if ( !pfnLoadLibrary )
  303.         return FALSE;
  304.     
  305.     PInjectionPage = FindUsablePage(ProcessInformation.hProcess,
  306.                                         ProcessDebugInfo.lpBaseOfImage);
  307.     if ( !PInjectionPage )
  308.         return FALSE;
  309.     
  310.     if ( !GetSpyDllName(szSpyDllName, sizeof(szSpyDllName)) )
  311.         return FALSE;
  312.  
  313.     OriginalThreadContext.ContextFlags = CONTEXT_CONTROL;
  314.     if ( !GetThreadContext(ProcessInformation.hThread,&OriginalThreadContext))
  315.         return FALSE;
  316.     
  317.     // =====================================================================
  318.     // Phase 2 - Saving the original code page away
  319.     // =====================================================================
  320.  
  321.     // Save off the original code page
  322.     retCode = ReadProcessMemory(ProcessInformation.hProcess, PInjectionPage,
  323.                                 OriginalCodePage, sizeof(OriginalCodePage),
  324.                                 &cBytesMoved);
  325.     if ( !retCode || (cBytesMoved != sizeof(OriginalCodePage)) )
  326.         return FALSE;
  327.  
  328.     // =====================================================================
  329.     // Phase 3 - Writing new code page and changing the thread context
  330.     // =====================================================================
  331.  
  332.     pNewCode = (PFAKE_LOADLIBRARY_CODE)NewCodePage;
  333.  
  334.     pNewCode->instr_SUB = 0xEC81;
  335.     pNewCode->operand_SUB_value = 0x1000;
  336.         
  337.     pNewCode->instr_PUSH = 0x68;
  338.     pNewCode->operand_PUSH_value = (DWORD)PInjectionPage
  339.                             + offsetof(FAKE_LOADLIBRARY_CODE, data_DllName);
  340.  
  341.     pNewCode->instr_CALL = 0xE8;
  342.     pNewCode->operand_CALL_offset =
  343.             (DWORD)pfnLoadLibrary - (DWORD)PInjectionPage
  344.             - offsetof(FAKE_LOADLIBRARY_CODE,instr_CALL) - 5;
  345.  
  346.     pNewCode->instr_INT_3 = 0xCC;
  347.  
  348.     lstrcpy(pNewCode->data_DllName, szSpyDllName); // Copy DLL name
  349.     
  350.     // Write out the new code page
  351.     retCode = WriteProcessMemory(ProcessInformation.hProcess, PInjectionPage,
  352.                                 &NewCodePage, sizeof(NewCodePage),
  353.                                 &cBytesMoved);
  354.     if ( !retCode || (cBytesMoved != sizeof(NewCodePage)) )
  355.         return FALSE;
  356.  
  357.     FakeLoadLibraryContext = OriginalThreadContext;
  358.     FakeLoadLibraryContext.Eip = (DWORD)PInjectionPage;
  359.     
  360.     if ( !SetThreadContext(ProcessInformation.hThread,
  361.                             &FakeLoadLibraryContext) )
  362.         return FALSE;
  363.     
  364.     return TRUE;
  365. }
  366.  
  367. BOOL ReplaceOriginalPagesAndContext(void)
  368. {
  369.     BOOL retCode;
  370.     DWORD cBytesMoved;
  371.     
  372.     retCode = WriteProcessMemory(ProcessInformation.hProcess, PInjectionPage,
  373.                                 OriginalCodePage, sizeof(OriginalCodePage),
  374.                                 &cBytesMoved);
  375.     if ( !retCode || (cBytesMoved != sizeof(OriginalCodePage)) )
  376.         return FALSE;
  377.  
  378.     if ( !SetThreadContext(ProcessInformation.hThread,
  379.                             &OriginalThreadContext) )
  380.         return FALSE;
  381.     
  382.     return TRUE;
  383. }
  384.  
  385. PVOID FindUsablePage(HANDLE hProcess, PVOID PProcessBase)
  386. {
  387.     DWORD peHdrOffset;
  388.     DWORD cBytesMoved;
  389.     IMAGE_NT_HEADERS ntHdr;
  390.     PIMAGE_SECTION_HEADER pSection;
  391.     unsigned i;
  392.     
  393.     // Read in the offset of the PE header within the debuggee
  394.     if ( !ReadProcessMemory(ProcessInformation.hProcess,
  395.                             (PBYTE)PProcessBase + 0x3C,
  396.                             &peHdrOffset,
  397.                             sizeof(peHdrOffset),
  398.                             &cBytesMoved) )
  399.         return FALSE;
  400.         
  401.     
  402.     // Read in the IMAGE_NT_HEADERS.OptionalHeader.BaseOfCode field
  403.     if ( !ReadProcessMemory(ProcessInformation.hProcess,
  404.                             (PBYTE)PProcessBase + peHdrOffset,
  405.                             &ntHdr, sizeof(ntHdr), &cBytesMoved) )
  406.         return FALSE;
  407.  
  408.     pSection = (PIMAGE_SECTION_HEADER)
  409.                 ((PBYTE)PProcessBase + peHdrOffset + 4
  410.                 + sizeof(ntHdr.FileHeader)
  411.                 + ntHdr.FileHeader.SizeOfOptionalHeader);
  412.         
  413.     for ( i=0; i < ntHdr.FileHeader.NumberOfSections; i++ )
  414.     {
  415.         IMAGE_SECTION_HEADER section;
  416.         
  417.         if ( !ReadProcessMemory( ProcessInformation.hProcess,
  418.                                  pSection, §ion, sizeof(section),
  419.                                  &cBytesMoved) )
  420.             return FALSE;
  421.  
  422.         // OutputDebugString( "trying section: " );
  423.         // OutputDebugString( section.Name );
  424.         // OutputDebugString( "\r\n" );
  425.  
  426.         // If it's writeable, and not the .idata section, we'll go with it
  427.         if ( (section.Characteristics & IMAGE_SCN_MEM_WRITE)
  428.              && strncmp(section.Name, ".idata", 6) )
  429.         {
  430.             // OutputDebugString( "using section: " );
  431.             // OutputDebugString( section.Name );
  432.             // OutputDebugString( "\r\n" );
  433.             
  434.             return (PVOID) ((DWORD)PProcessBase + section.VirtualAddress);
  435.         }
  436.  
  437.         pSection++; // Not this section.  Advance to next section.
  438.     }
  439.  
  440.     return 0;
  441. }
  442.  
  443. BOOL GetSpyDllName(PSTR buffer, UINT cBytes)
  444. {
  445.     char szBuffer[MAX_PATH];
  446.     PSTR pszFilename;
  447.     
  448.     // Get the complete path to this EXE - The spy dll should be in the
  449.     // same directory.
  450.     GetModuleFileName(0, szBuffer, sizeof(szBuffer));
  451.  
  452.     pszFilename = strrchr(szBuffer, '\\');
  453.     if ( !pszFilename )
  454.         return FALSE;
  455.     
  456.     lstrcpy(pszFilename+1, "APISPY32.DLL");
  457.     strncpy(buffer, szBuffer, cBytes);
  458.     return TRUE;
  459. }
  460.  
  461.